/**
 *    Copyright (C) 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_TOOLS_CONFIGURATOR_HPP
#define	_CUBEFS_CORE_API_TOOLS_CONFIGURATOR_HPP

#include <cubefs/api/exceptions.hpp>
#include <cubefs/api/tools/configurator.hpp>
#include <cubefs/api/tools/strings.hpp>
#include <cubefs/core/tools/configurator.hpp>
#include <cubefs/core/api/reflection/type.hpp>

#define CUBEFS_SOURCE "cubefs/core/api/tools/configurator.hpp:" CUBEFS_AT

namespace cubefs    {
namespace api       {

using cubefs::tools::Configurator;


template <typename Interface>
class ConfigurationImplT: public TypedImplT<Interface> {

	typedef ConfigurationImplT<Interface> 	Me;
    typedef TypedImplT<Interface> 			Base;

public:
    ConfigurationImplT(cubefs::tools::Configurator* cfg): Base(), configurator_(cfg), exceptions_(true) {}

	virtual bool AreExceptionsEnabled() const {
		return exceptions_;
	}

	virtual void SetExceptionsEnabled(bool enabled) {
		this->exceptions_ = enabled;
	}

	virtual Configuration* GetParent() const
	{
		Configurator* parent = configurator_->GetParent();
		if (parent != NULL) {
			return parent->GetApiPair();
		}
		else {
			return NULL;
		}
	}

	virtual bool IsPropertyDefined(StringRef name) const {
		return configurator_->IsPropertyDefined(name);
	}

	virtual String GetProperty(StringRef name) const {
		return configurator_->GetProperty(name);
	}

	virtual void AddProperty(StringRef name, StringRef value) {
		configurator_->AddProperty(name, value);
	}

	virtual void RemoveProperty(StringRef name) {
		configurator_->RemoveProperty(name);
	}

	virtual ListOfStrings* GetPropertyList() const
	{
		const Configurator* cfg = this->configurator_;

		CoreFactory* factory = GetCoreFactory();

		ListOfStrings* list = factory->CreateListOfStrings();

		while (cfg != NULL)
		{
			for (Configurator::StringMapType::const_iterator i = cfg->GetThisConfigurationProperties().begin(); i != cfg->GetThisConfigurationProperties().end(); i++)
			{
				list->Add(factory->Create(i->first));
			}
			cfg = cfg->GetParent();
		}

		return list;
	}

	ListOfStrings* parse(StringRef str, StringRef separators) const
	{
		CoreFactory* factory = GetCoreFactory();
		ListOfStrings* list = factory->CreateListOfStrings();

		String::size_type pos = 0;
		while (pos != String::npos && pos < str.length())
		{
			String::size_type idx = str.find_first_of(separators, pos);

			StringValue* value;

			if (idx != String::npos)
			{
				value = factory->Create(TrimString(str.substr(pos, idx - pos)));
				pos = idx + 1;
			}
			else {
				value = factory->Create(TrimString(str.substr(pos, str.length() - pos)));
				pos = String::npos;
			}

			list->Add(value);
		}
	}

	virtual ListOfStrings* ParsePathList(StringRef list) const {
		return parse(list, Configurator::GetPathSeparatorChar());
	}

	virtual ListOfStrings* ParseValueList(StringRef list) const {
		return parse(list, ",");
	}

    static void InitType() {
    	type_ = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
    }

    static void InitOperations() {
    	AbstractType *type = static_cast<AbstractType*>(type_);

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(), Configuration* (Me::*)() const>(type, Configuration::MyType(), "GetParent", &Me::GetParent));
    	type->AddOperation(new BasicOperation<bool (Me::*)(String), bool (Me::*)(StringRef) const>(type, "IsPropertyDefined", "name", &Me::IsPropertyDefined));

    	type->AddOperation(new BasicOperation<String (Me::*)(String), String (Me::*)(StringRef) const>(type, "GetProperty", "name", &Me::GetProperty));
    	type->AddOperation(new BasicOperation<void (Me::*)(String, String), void (Me::*)(StringRef, StringRef)>(type, "AddProperty", "name", "value", &Me::AddProperty));
    	type->AddOperation(new BasicOperation<void (Me::*)(String), void (Me::*)(StringRef)>(type, "RemoveProperty", "name", &Me::RemoveProperty));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(), ListOfStrings* (Me::*)() const>(type, NULL, "GetPropertyList", &Me::GetPropertyList));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(String), ListOfStrings* (Me::*)(StringRef) const>(type, ListOfStrings::MyType(), "ParsePathList", "list", &Me::ParsePathList));
    	type->AddOperation(new BasicOperation<Typed* (Me::*)(String), ListOfStrings* (Me::*)(StringRef) const>(type, ListOfStrings::MyType(), "ParseValueList", "list", &Me::ParseValueList));
    }


    CUBEFS_DECLARE_REFLECTION;

private:
    cubefs::tools::Configurator* configurator_;
    bool exceptions_;
};


template <typename Interface>
Type* ConfigurationImplT<Interface>::type_						= NULL;

typedef ConfigurationImplT<Configuration>						ConfigurationImpl;

}
}

#undef CUBEFS_SOURCE
#endif
